/**
 * ======================================================================
 * 【基本说明】：
 * MobileIMSDK-Web版服务端的在线用户列表实现类。
 *
 * Created by Jack Jiang on 16-8-29.
 * ======================================================================
 */

var imutils = require('./send-util-local');
var logger = require('../j_conf/log').logger;
var HasMapClass = require('../j_common/hashmap');
var ProtocalFactory = require('./protocal-factory');


function UserProcessor(){
    // 用户在线列表：key=userId、value=socket会话实例引用
    this.userSessions = new HasMapClass();
}

/**
 * 将用户放入在线列表。
 *
 * @param user_id 用户的user_id，由登陆时提交，全局唯一
 * @param session 该用户对应的MINA会话引用
 */
UserProcessor.prototype.putUser = function(user_id, socket){
    if(this.userSessions.contains(user_id)){
        // 之前已经登陆了此账号的连接对象引用
        var previousSocket = this.userSessions.get(user_id);

        logger.debug("[SDKUsers]【注意】用户id="+user_id+"已经在在线列表中了，session也是同一个吗(%s)？"
            , (previousSocket.id == socket.id));

        // 如果当前正在提交登陆（将要加到在线列表）的socket与已存在于在线列表中的socket的id是一样的
        // ，即意味着这可能是同一socket因某种原因的重复提交，本次可以正常忽略putUser了
        if(previousSocket.id == socket.id){
            logger.info("[SDKUsers]【注意】用户id="+user_id+"已经在在线列表中了，" +
                "但当前的登陆socket居然跟已存在于在线列表中的socekt的id是一样，这意味着是" +
                "同一个socket因某种原因的重复提交，本次UserProcessor.putUser可以正常忽略了哦!");
        }
        // 否则踢掉之前的登陆连接
        else{
            // 将被踢下线的消息反馈给之前的客户端（以备它在ui上给用户以友好的反馈）
            imutils.sendData1(previousSocket, ProtocalFactory.createDuplicatedLoginResponse(user_id));
            // 同时关掉它的网络连接
            // 补充：因Socket.io的底层网络机制，客户端此时不能主动关闭连接，不然服务
            // 端无法触发它的disconnect事件（客户端事件也会不正常）。而服务端也不要
            // 立即关闭，延迟几秒以备客户端处理完上面的消息事件
            imutils.lazyCloseSocket(previousSocket, '[IMCORE]【注意】用户id='
                +user_id+'('+previousSocket.id+')已被踢下线且通信关闭！');
        }
    }

    // 将用户加入到在线列表中
    this.userSessions.put(user_id, socket);

    // TODO ------------------------------------- just for DEBUG
    this.userSessions.showAll(funValueToString);
};

/**
 * 将用户从在线列表中移除.
 *
 * @param user_id 用户的user_id
 * @return true表示已成功remove，否则表示没有此user_id对应的在线信息
 */
UserProcessor.prototype.removeUser = function (user_id) {
    if (!this.userSessions.contains(user_id))
    {
        logger.warn("[SDKUsers]！用户id=" + user_id + "不存在在线列表中，本次removeUser没有继续.");

        // TODO ------------------------------------- just for DEBUG
        this.userSessions.showAll(funValueToString);

        return false;
    }
    else
    {
        var removeOK = this.userSessions.remove(user_id);
        logger.warn("[SDKUsers]！用户id=" + user_id + "已从在线列表中remove?"+removeOK);

        // TODO ------------------------------------- just for DEBUG
        this.userSessions.showAll(funValueToString);

        return removeOK;
    }
};

/**
 * 根据user_id获得该在线用户对应的socket会话实例句柄。
 *
 * @param user_id 用户的user_id
 * @return 存在该在线用户则成功返回，否则返回null
 */
UserProcessor.prototype.getSession = function (user_id) {
    // TODO ------------------------------------- just for DEBUG
    logger.debug("[UserProcessor.getSession]======>user_id="+user_id+"在列表中吗？"+this.userSessions.contains(user_id));
    this.userSessions.showAll(funValueToString);
    return this.userSessions.get(user_id);
};

/**
 * 该用户会话是否是合法的（已登陆认证）。
 * <p>
 * 根据MINA的原理，任何请求都会建立会话，但会话是否是合法的，则需根据
 * 存放于其会话中的登陆属性来校验（MobileIMSDK中，已经过登陆认证的会话
 * ，会在其session中存放user_id，判断是否已设置user_id即可认定是否是
 * 合法的会话）。
 *
 * @param session 用户的socket.io的socket会话引用
 * @return true表示已经成功登陆认证过，否则表示未登陆过（非法请求）
 */
UserProcessor.prototype.isLogined = function (session) {
    // TODO ------------------------------------- just for DEBUG
    logger.debug("[UserProcessor.isLogined]======>session="+session
        +", this.getUserIdFromSession(session)？"+this.getUserIdFromSession(session));
    //this.userSessions.showAll();

    return session && this.getUserIdFromSession(session);
};

/**
 * 尝试取出存放于用户会话中的user_id.通常只有已成功登陆验证后的用户
 * 会话中才会存放它对应的user_id.
 *
 * @param session 用户的socket.io的socket会话引用
 * @return 如果找到该属性则返回指定session的user_id，否则返回null
 */
UserProcessor.prototype.getUserIdFromSession = function (session) {
    var attr = null;
    if(session != null)
    {
        attr = session.userId;
        if(attr){
            return attr;
        }
    }
    return attr;
};

/**
 * 指定用户ID的用户是否在线。
 *
 * @param userId 用户名ID（就是用户登陆名）
 * @return true表示该用户在线，否则不在线
 * @since 3.0
 */
UserProcessor.prototype.isOnline = function(userId)
{
    if(this.getSession(userId))
        return true;
    else
        return false;
};


// just for debug
function funValueToString(valueInHash){
    if(valueInHash){
        return valueInHash.id;
    }
}


module.exports = UserProcessor;
